﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Parallel3M.parallel3m.framework;
using System.Collections;
using System.Xml;

namespace Parallel3M.parallel3m.payload
{
    public class PayloadGraph:ParallelPayload
    {
        
        //payload graph structures
        public Hashtable payloadNodes = new Hashtable();
        public int completedCount = 0;

        public PayloadNode head=new PayloadNode();

        public PayloadGraph()
        {
            payloadNodes.Add("head", head);
        }

        public void addPayloadNode(ParallelPayload payload)
        {
            PayloadNode node = new PayloadNode();            
            node.payload = payload;
            payloadNodes.Add(payload.id, node);
        }

        public void addPrePayloadNode(PayloadNode node, PayloadNode prenode)
        {
            node.inputNodes.Add(prenode);
        }

        public void addPostPayloadNode(PayloadNode node, PayloadNode postnode)
        {
            node.outputNodes.Add(postnode);
        }
                
        //cycle update
        public ArrayList update(ParallelPayload payload)
        {
            ArrayList readyPayloads = new ArrayList();

            if (payload != null)
            {
                completedCount++;
                PayloadNode node = (PayloadNode)payloadNodes[payload.id];
                node.status = PAYLOADNODECONSTANT.STATUS_COMPLETED;


                //update the response from payload node to response of graph
                UpdateResponse(payload);

                if (completedCount == payloadNodes.Count-1)
                {
                    isCompleted = true;
                }
                else
                {
                    foreach (PayloadNode postnode in node.outputNodes)
                    {
                        bool isReady = true;
                        foreach (PayloadNode prenode in postnode.inputNodes)
                        {
                            if (prenode.status != PAYLOADNODECONSTANT.STATUS_COMPLETED)
                            {
                                isReady = false;
                            }
                        }
                        if (isReady)
                        {
                            //update the request of the ready payload
                            UpdateRequest(postnode.payload);
                            //
                            readyPayloads.Add(postnode.payload);
                        }
                    }
                }
            }
            
            return readyPayloads;
        }


        public virtual void UpdateResponse(ParallelPayload payload)
        {
            response += "<payload id='"+payload.id +"'>" + payload.response + "</payload>";
        }

        public virtual void UpdateRequest(ParallelPayload payload)
        {

        }

        /*
         * 
         *  <payloadgraph id="PL1" timestamp="" routeTag="graph" domain="*" type="request" handlerid="graph" access="Public" language="c#">
                <request>         *          
         *          <payloadnode name="a1">
         *              <payload/>
         *          </payloadnode>
         *          <payloadnode name="a2">
         *              <payload/>
         *          </payloadnode>          
         *          <payloadconnection from="start" to="a1"/>
         *          <payloadconnection from="start" to="a2"/>
         *          <payloadconnection from="a1" to="a2"/>
         *      </request>
         *      <response>
         *           <V1>vlue</V1>
         *           <V2>value</V2>
         *      </response> 
            </payloadgraph> 
         * 
         */
        public override void parse(XmlNode node)
        {
            XmlAttributeCollection atts = node.Attributes;
            Hashtable attTable = new Hashtable();
            foreach (XmlAttribute att in atts)
            {
                attTable.Add(att.Name, att.Value);
            }
            id = (String)attTable["id"];
            if (id == null || id == "")
            {
                id = Guid.NewGuid().ToString();
            }
            try
            {
                timestamp = long.Parse((string)attTable["timestamp"]);
            }
            catch (Exception e)
            {
                timestamp = -1;
            }
            routeTag = (String)attTable["routeTag"];
            if (routeTag == null)
            {
                routeTag = PAYLOADCONSTRANT.DEFAULT_ROUTETAG;
            }

            domain = (String)attTable["domain"];
            type = (String)attTable["type"];
            access = (String)attTable["access"];
            handlerid = (String)attTable["handlerid"];
            language = (String)attTable["language"];

            foreach (XmlNode childnode in node.ChildNodes)
            {
                if (childnode.Name == "request")
                {
                    //transfer to graph node
                    ArrayList connections = new ArrayList();
                    foreach (XmlNode payloadnode in childnode)
                    {
                        if (payloadnode.Name == "payloadnode")
                        {
                            PayloadNode node_pl = new PayloadNode();
                            node_pl.parse(payloadnode);
                            payloadNodes.Add(node_pl.name, node_pl);
                        }
                        else if (payloadnode.Name == "payloadconnection")
                        {
                            Hashtable connAttributes = new Hashtable();
                            XmlAttributeCollection connatts = payloadnode.Attributes;
                            foreach (XmlAttribute att in connatts)
                            {
                                connAttributes.Add(att.Name, att.Value);
                            }
                            connections.Add(connAttributes);
                        }
                    }

                    foreach (Hashtable conn in connections)
                    {
                        String from = (String)conn["from"];
                        String to = (String)conn["to"];

                        PayloadNode fromNode = (PayloadNode)payloadNodes[from];
                        PayloadNode toNode = (PayloadNode)payloadNodes[to];

                        fromNode.outputNodes.Add(toNode);
                        toNode.inputNodes.Add(fromNode);                        

                    }

                }
                else if (childnode.Name == "response")
                {
                    response = childnode.InnerText;
                }
            }


        }


    }
}
